package sketchpad.business.datacalc.calchelper.impl;

import sketchpad.business.datacalc.calchelper.CalcHelperService;
import sketchpad.business.datacalc.calchelper.impl.featurenode.AddFeatureNodeUtil;
import sketchpad.constant.Config;
import sketchpad.constant.Geometry;
import sketchpad.constant.SketchPadException;
import sketchpad.gui.control.DrawControl;
import sketchpad.gui.drawinggraph.*;
import sketchpad.gui.drawinggraph.node.Node;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

//计算辅助类
public final class CalcHelperServiceImpl implements CalcHelperService {

    private DrawControl control;

    public CalcHelperServiceImpl(DrawControl drawControl){
        control  = drawControl;
    }

    //根据鼠标坐标画长方形选择框，返回所有顶点在选择框中的图形
    //对于每一种图形，取几个特征点与选择框比较以便减少计算
    @Override
    public List<Integer> multiSelect(Node node1, Node node2){
        selectRectX1 = Math.min(node1.x, node2.x);
        selectRectX2 = Math.max(node1.x, node2.x);
        selectRectY1 = Math.min(node1.y,node2.y);
        selectRectY2 = Math.max(node1.y, node2.y);
        List<DrawItem> list = new ArrayList<>(control.getDrawItemMap().values());
        List<Integer> re = new ArrayList<>();
        for (DrawItem item : list){
            AddFeatureNodeUtil.getFeatureNode().clear();
            if (item.getId()== Config.SELECT_ID)continue;
            switch (item.getGeometryClass()){
                case CIRCLE:
                    AddFeatureNodeUtil.addFeatureNodeWhenCircle(item);
                    break;
                case RECTANGLE:
                    AddFeatureNodeUtil.addFeatureNodeWhenRectangle(item);
                    break;
                case TRIANGLE:
                    AddFeatureNodeUtil.addFeatureNodeWhenTriangle(item);
                    break;
                case RANDOM:
                    AddFeatureNodeUtil.addFeatureNodeWhenRandom(item);
                    break;
            }
            for (Node node : AddFeatureNodeUtil.getFeatureNode()){
                if (pointInSelectBox(node.x,node.y)){
                    re.add(item.getId());
                    break;
                }
            }
        }

        return re;
    }

    private double selectRectX1 = 0;
    private double selectRectY1 = 0;
    private double selectRectX2 = 0;
    private double selectRectY2 = 0;
    private boolean pointInSelectBox(double x, double y){
        return (x>=selectRectX1 && x<=selectRectX2) && (y>=selectRectY1 && y<=selectRectY2);
    }

    //将组合的图形放入，并且算出所选图形的最小和最大点的坐标
    @Override
    public void addGroupMemberAfterSelect(Node minCorNode, Node maxCorNode){
        List<Integer> selectedList = control.getSelectedItemList();
        List<Integer> newSelectedList = new ArrayList<>();
        Map<Integer, Group> groupMap = control.getGroupMap();
        Map<Integer, DrawItem> itemMap = control.getDrawItemMap();
        for (Integer i : selectedList){
            if (!newSelectedList.contains(i)){
                DrawItem item = itemMap.get(i);
                if (groupMap.containsKey(item.getGroupId())){
                    List<DrawItem> itemList = groupMap.get(item.getGroupId()).getItemList();
                    for (DrawItem item1 : itemList){
                        newSelectedList.add(item1.getId());
                        findCor(item1,minCorNode,maxCorNode);
                    }
                }else{
                    newSelectedList.add(i);
                    findCor(item, minCorNode,maxCorNode);
                }
            }
        }
        control.setSelectedItemList(newSelectedList);
    }

    private static void findCor(DrawItem item, Node minCorNode, Node maxCorNode){
        if (item.getGeometryClass()== Geometry.RANDOM){
            List<Node> nodes = ((Random)item).getNodeList();
            for (Node node1 : nodes){
                minCorNode.x = Math.min(minCorNode.x, node1.x);
                minCorNode.y = Math.min(minCorNode.y, node1.y);
                maxCorNode.x = Math.max(maxCorNode.x, node1.x);
                maxCorNode.y = Math.max(maxCorNode.y, node1.y);
            }
        }else {
            double x1 = item.getLeftUpNode().x;
            double y1 = item.getLeftUpNode().y;
            double x2 = item.getRightDownNode().x;
            double y2 = item.getRightDownNode().y;

            minCorNode.y = Math.min(Math.min(y1,y2),minCorNode.y);
            maxCorNode.y = Math.max(Math.max(y1,y2),maxCorNode.y);

            if (item.getGeometryClass() == Geometry.TRIANGLE) {
                double x3 = x1+x1-x2;
                minCorNode.x = Math.min(Math.min(x2,x3),minCorNode.x);
                maxCorNode.x = Math.max(Math.max(x2,x3),maxCorNode.x);
            } else {
                minCorNode.x = Math.min(Math.min(x2,x1),minCorNode.x);
                maxCorNode.x = Math.max(Math.max(x2,x1),maxCorNode.x);
            }
        }
    }

    /*
    * 对选中的图形进行修复，应该首先判断选中图形情况：
    * 1、如果包含基本图形就不进行修复
    * 2、严格限制：根据笔画数量进行修复而且圆形不能歪
    * @return 自定义提示内容
    * */
    @Override
    public SketchPadException fixDrawItem(Geometry form){
        if (form==Geometry.RANDOM)return SketchPadException.NO_LOGIC_EXCEPTION;
        double xmin = Double.MAX_VALUE;
        double xmax = Double.MIN_VALUE;
        double ymin = Double.MAX_VALUE;
        double ymax = Double.MIN_VALUE;
        for (int id : control.getSelectedItemList()){
            DrawItem item = control.getDrawItemMap().get(id);
            if (item.getGeometryClass()!=Geometry.RANDOM)return SketchPadException.TRANSFORM_CONTAIN_BASIC_ITEM;
            for (Node node : ((Random)item).getNodeList()){
                xmax = Math.max(xmax, node.x);
                xmin = Math.min(xmin, node.x);
                ymin = Math.min(ymin, node.y);
                ymax = Math.max(ymax, node.y);
            }
        }
        //delete them
        for (int id : control.getSelectedItemList()){
            control.getDrawItemMap().remove(id);
        }
        control.getSelectedItemList().clear();
        //substitute with a new item
        DrawItem item;
        switch (form){
            case CIRCLE:
                item = new Circle(control.getGlobalId(),new Node(xmin, ymin));
                item.setRightDownNode(new Node(xmax, ymax));
                break;
            case RECTANGLE:
                item = new Rectangle(control.getGlobalId(),new Node(xmin, ymin));
                item.setRightDownNode(new Node(xmax, ymax));
                break;
            case TRIANGLE:
                item = new Triangle(control.getGlobalId(),new Node((xmin+xmax)/2, ymin));
                item.setRightDownNode(new Node(xmax, ymax));
                break;
            default:
                item = null;
        }
        control.getDrawItemMap().put(item==null?Integer.MIN_VALUE:item.getId(), item);
        control.drawAllItem();
        return SketchPadException.NO_LOGIC_EXCEPTION;
    }

    @Override
    public DrawItem modifyNewCor(DrawItem item, double deltX, double deltY){
        if (item.getGeometryClass()== Geometry.RANDOM){
            List<Node> list = ((Random)item).getNodeList();
            for (Node node1 : list){
                node1.x += deltX;
                node1.y += deltY;
            }
        }else{
            Node leftUpNode = item.getLeftUpNode();
            Node rightDownNode = item.getRightDownNode();
            item.setLeftUpNode(new Node(leftUpNode.x+deltX, leftUpNode.y+deltY));
            item.setRightDownNode(new Node(rightDownNode.x+deltX, rightDownNode.y+deltY));
        }
        return item;
    }
}
